package com.gitee.qdbp.general.system.biz.personnel.service;

import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.gitee.qdbp.able.exception.ServiceException;
import com.gitee.qdbp.able.result.ResultCode;
import com.gitee.qdbp.base.model.consts.Keys;
import com.gitee.qdbp.base.system.model.IAccount;
import com.gitee.qdbp.general.common.api.sequence.model.SimpleSequenceRule;
import com.gitee.qdbp.general.common.api.sequence.service.ISimpleSequenceGenerator;
import com.gitee.qdbp.general.system.api.personnel.basic.IDepartmentCoreBasic;
import com.gitee.qdbp.general.system.api.personnel.model.DepartmentCoreBean;
import com.gitee.qdbp.general.system.api.personnel.model.DepartmentCoreUpdate;
import com.gitee.qdbp.general.system.api.personnel.model.DepartmentCoreWhere;
import com.gitee.qdbp.general.system.api.personnel.service.IDepartmentCoreExecutor;
import com.gitee.qdbp.general.system.api.personnel.service.IDepartmentCoreQueryer;
import com.gitee.qdbp.general.system.error.PersonnelErrorCode;
import com.gitee.qdbp.tools.utils.StringTools;
import com.gitee.qdbp.tools.utils.VerifyTools;

/**
 * 部门信息业务处理类
 *
 * @author zhh
 * @version 170215
 */
@Service
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public class DepartmentCoreExecutor implements IDepartmentCoreExecutor {

    /** 日志对象 **/
    private static final Logger log = LoggerFactory.getLogger(DepartmentCoreExecutor.class);

    /**
     * 编号初始值<br>
     * 用于版本升级时兼容原先的编号机制<br>
     * 例如升级前最大的编号已达到40, 那么可以设置初始值为50
     */
    private int deptCodeInitValue = 1;

    /** 部门编号第1位数字是几, 只允许1~9 **/
    private int deptCodeFirstDigit = 1;

    /** 部门信息DAO **/
    @Autowired
    private IDepartmentCoreBasic departmentCoreBasic;

    @Autowired
    private ISimpleSequenceGenerator sequenceGenerator;

    @Override
    public void create(DepartmentCoreBean model, IAccount me) throws ServiceException {
        String msg = "Failed to create DepartmentCore. ";

        if (VerifyTools.isBlank(me)) {
            log.error(msg + "params is null: me");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(model)) {
            log.error(msg + "params is null: model");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        // 判断DeptName不能为空
        if (VerifyTools.isBlank(model.getDeptName())) {
            log.error(msg + "params is null: DeptName");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        String tenantCode = me.getTenantCode();

        String parentCode = model.getParentCode();
        if (VerifyTools.isBlank(parentCode)) {
            parentCode = Keys.ROOT_CODE;
            model.setParentCode(parentCode);
        }

        String deptCode = model.getDeptCode();
        if (VerifyTools.isBlank(deptCode)) { // 自动生成部门编号
            if (Keys.ROOT_CODE.equals(parentCode)) { // 顶级部门
                // 生成顶级部门编号
                deptCode = createDeptCode(tenantCode, parentCode);
            } else {
                // 验证: 上级部门是否存在
                checkDeptExist(null, parentCode);
                // 生成部门编号: 上级部门编号加n位序号
                deptCode = createDeptCode(tenantCode, parentCode);
            }
            model.setDeptCode(deptCode);
        } else { // 外部传入部门编号
            int codeLength = IDepartmentCoreQueryer.DEPT_CODE_LENGTH;
            if (Keys.ROOT_CODE.equals(parentCode)) { // 顶级部门
                // 检查部门编号
                if (deptCode.length() < codeLength) {
                    deptCode = StringTools.pad(deptCode, '0', codeLength);
                } else if (deptCode.length() > codeLength) {
                    log.error(msg + "root dept code too long: [{}]", deptCode);
                    throw new ServiceException(PersonnelErrorCode.DEPT_CODE_TOO_LONG);
                }
            } else {
                // 验证: 上级部门是否存在
                checkDeptExist(null, parentCode);
                // 检查部门编号
                if (deptCode.length() % codeLength != 0) {
                    deptCode = StringTools.pad(deptCode, '0', (deptCode.length() / codeLength + 1) * codeLength);
                }
                if (!deptCode.startsWith(parentCode)) {
                    log.error(msg + "sub dept code [{}] must starts with parent [{}]", deptCode, parentCode);
                    throw new ServiceException(PersonnelErrorCode.DEPT_CODE_MUST_STARTS_WITH_PARENT);
                }
            }
        }

        // 验证: 部门名称在同一上级部门下不能重复
        checkDeptName(null, tenantCode, parentCode, model.getDeptName());

        model.setTenantCode(me.getTenantCode());
        model.setId(null); // ID不允许指定
        model.setCreateTime(null); // 数据库默认值
        model.setCreatorId(me.getId());
        model.setCreatorName(me.getDisplayName());

        // 向sys_department_core_info表插入记录
        departmentCoreBasic.create(model);

    }

    @Override
    public void update(DepartmentCoreUpdate model, IAccount me) throws ServiceException {
        String msg = "Failed to update DepartmentCore. ";

        if (VerifyTools.isBlank(me)) {
            log.error(msg + "params is null: me");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(model)) {
            log.error(msg + "params is null: model");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        String id = model.getId();
        if (VerifyTools.isBlank(id) && model.getWhere() != null) {
            id = model.getWhere().getId();
        }
        String deptCode = model.getDeptCode();
        if (VerifyTools.isBlank(deptCode) && model.getWhere() != null) {
            deptCode = model.getWhere().getDeptCode();
        }
        if (VerifyTools.isAllBlank(id, deptCode)) {
            log.error(msg + "id or deptCode is required.");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        // 原始记录检查
        DepartmentCoreBean older;
        if (VerifyTools.isNotBlank(id)) {
            older = departmentCoreBasic.findById(id);
            if (older == null) {
                log.error(msg + "record is not found. id=" + id);
                throw new ServiceException(ResultCode.RECORD_NOT_EXIST);
            }
        } else {
            older = departmentCoreBasic.findByDeptCode(deptCode);
            if (older == null) {
                log.error(msg + "record is not found. deptCode=" + deptCode);
                throw new ServiceException(ResultCode.RECORD_NOT_EXIST);
            }
        }

        String tenantCode = me.getTenantCode();

        DepartmentCoreUpdate newer = createChangedModel(model, older);

        if (newer != null) {
            if (VerifyTools.isNotBlank(newer.getDeptName())) {
                // 验证: 部门名称如果有修改则在同一上级部门下不能重复
                checkDeptName(older.getDeptCode(), tenantCode, model.getParentCode(), model.getDeptName());
            }
            // 更新sys_department_core_info表的记录
            departmentCoreBasic.update(newer, false);
        }

    }

    @Override
    public void delete(String id, IAccount me) throws ServiceException {
        String msg = "Failed to delete DepartmentCore. ";

        if (VerifyTools.isBlank(me)) {
            log.error(msg + "params is null: me");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(id)) {
            log.error(msg + "params is null: id");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        // 从sys_department_core_info表查询原记录
        DepartmentCoreBean older = departmentCoreBasic.findById(id);
        if (older == null) {
            log.error(msg + "record is not found.\n\tid is " + id);
            throw new ServiceException(ResultCode.RECORD_NOT_EXIST);
        }

        // 删除sys_department_core_info表的记录
        departmentCoreBasic.deleteByIds(Arrays.asList(id), false);

    }

    @Override
    public void delete(List<String> ids, IAccount me) throws ServiceException {
        String msg = "Failed to delete DepartmentCore. ";

        if (VerifyTools.isBlank(me)) {
            log.error(msg + "params is null: me");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(ids)) {
            log.error(msg + "params is null: ids");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        // 删除sys_department_core_info表的记录
        departmentCoreBasic.deleteByIds(ids, false);

    }

    /**
     * 生成部门编号: 上级部门编号加n位序号
     *
     * @param tenantCode 租户编号
     * @param parentCode 上级部门
     * @return 部门编号
     * @throws ServiceException
     */
    protected String createDeptCode(String tenantCode, String parentCode) throws ServiceException {

        if (VerifyTools.isBlank(parentCode)) {
            parentCode = Keys.ROOT_CODE;
        }

        int codeLength = IDepartmentCoreQueryer.DEPT_CODE_LENGTH;
        SimpleSequenceRule rule = getDeptSequenceRule(tenantCode, parentCode);
        String nextCode = sequenceGenerator.use(rule).generate("DEPT", tenantCode, parentCode);
        int prefixLength = rule.getPrefix() == null ? 0 : rule.getPrefix().length();
        if (nextCode.length() - prefixLength > codeLength) {
            log.error("Department code out of max limit. parentCode:[{}], codeLength:[{}]", parentCode, codeLength);
            throw new ServiceException(PersonnelErrorCode.DEPT_CODE_OUT_OF_MAX_LIMIT);
        }
        return nextCode;
    }

    protected SimpleSequenceRule getDeptSequenceRule(String tenantCode, String parentCode) {
        int codeLength = IDepartmentCoreQueryer.DEPT_CODE_LENGTH;
        SimpleSequenceRule rule;
        if (parentCode.equals(Keys.ROOT_CODE)) {
            // 1000 + deptCodeInitValue
            int first = Math.max(1, Math.min(9, deptCodeFirstDigit));
            rule = new SimpleSequenceRule((int) (Math.pow(10, codeLength - 1)) * first + deptCodeInitValue);
        } else {
            rule = new SimpleSequenceRule(deptCodeInitValue, parentCode, codeLength);
        }
        rule.setName("部门编号");
        return rule;
    }

    /**
     * 检查部门名称, 部门名称在同一上级部门下不能重复
     *
     * @param tenantCode 租户编号
     * @param parentCode 上级部门
     * @param deptName 部门名称
     * @throws ServiceException
     */
    private void checkDeptName(String deptCode, String tenantCode, String parentCode, String deptName)
            throws ServiceException {
        DepartmentCoreWhere model = new DepartmentCoreWhere();
        model.setTenantCode(tenantCode);
        model.setParentCode(parentCode);
        model.setDeptName(deptName);
        DepartmentCoreBean result = departmentCoreBasic.find(model);
        if (result != null && deptCode != null && !deptCode.equals(result.getDeptCode())) {
            log.warn("Department name is exist, deptName={}", deptName);
            throw new ServiceException(PersonnelErrorCode.DEPT_NAME_IS_EXIST);
        }
    }

    /**
     * 检查部门是否存在, 不存在则报错
     *
     * @param tenantCode 租户编号
     * @param deptCode 部门编号
     * @throws ServiceException
     */
    private DepartmentCoreBean checkDeptExist(String tenantCode, String deptCode) throws ServiceException {

        DepartmentCoreWhere model = new DepartmentCoreWhere();
        model.setTenantCode(tenantCode);
        model.setDeptCode(deptCode);

        DepartmentCoreBean bean = departmentCoreBasic.find(model);

        if (bean == null) {
            log.warn("部门信息不存在, deptCode=" + deptCode);
            throw new ServiceException(PersonnelErrorCode.DEPT_NOT_EXIST);
        }
        return bean;
    }

    public int getDeptCodeInitValue() {
        return deptCodeInitValue;
    }

    public void setDeptCodeInitValue(int deptCodeInitValue) {
        this.deptCodeInitValue = deptCodeInitValue;
    }

    public int getDeptCodeFirstDigit() {
        return deptCodeFirstDigit;
    }

    public void setDeptCodeFirstDigit(int deptCodeFirstDigit) {
        this.deptCodeFirstDigit = deptCodeFirstDigit;
    }

    /**
     * 创建一个新的对象, 只包含改动过的字段
     *
     * @author zhh
     * @param model 目标对象(一般是参数传入的)
     * @param older 源对象(一般是从数据库查询得到的)
     * @return 只包含有更新的字段对象
     */
    private DepartmentCoreUpdate createChangedModel(DepartmentCoreUpdate model, DepartmentCoreBean older) {
        DepartmentCoreUpdate newer = new DepartmentCoreUpdate();
        newer.setWhere(model.getWhere());

        boolean changed = false;
		DepartmentCoreWhere where = newer.getWhere(true);
		where.setTenantCode(model.getTenantCode()); // 租户编号
        where.setId(model.getId()); // 部门ID
        where.setDeptCode(model.getDeptCode()); // 部门编号

        // if (VerifyTools.isChanged(model.getTenantCode(), older.getTenantCode())) {
        //     changed = true;
        //     newer.setTenantCode(model.getTenantCode()); // 租户编号
        // }
        if (VerifyTools.isChanged(model.getDeptName(), older.getDeptName())) {
            changed = true;
            newer.setDeptName(model.getDeptName()); // 部门名称
        }
        // if (VerifyTools.isChanged(model.getParentCode(), older.getParentCode())) {
        //     changed = true;
        //     newer.setParentCode(model.getParentCode()); // 上级部门编号
        // }
        if (VerifyTools.isChanged(model.getSortIndex(), older.getSortIndex())) {
            changed = true;
            newer.setSortIndex(model.getSortIndex()); // 排序号(越小越靠前)
        }
        // if (VerifyTools.isChanged(model.getCreatorId(), older.getCreatorId())) {
        //     changed = true;
        //     newer.setCreatorId(model.getCreatorId()); // 创建人ID
        // }
        // if (VerifyTools.isChanged(model.getCreatorName(), older.getCreatorName())) {
        //     changed = true;
        //     newer.setCreatorName(model.getCreatorName()); // 创建人姓名
        // }
        // if (VerifyTools.isChanged(model.getCreateTime(), older.getCreateTime())) {
        //     changed = true;
        //     newer.setCreateTime(model.getCreateTime()); // 创建时间
        // }
        // if (VerifyTools.isChanged(model.getDataState(), older.getDataState())) {
        //     changed = true;
        //     newer.setDataState(model.getDataState()); // 数据状态:0为正常|其他为删除
        // }
        // if (Boolean.TRUE.equals(model.isTenantCodeToNull())) {
        //     changed = true;
        //     newer.setTenantCodeToNull(true); // 租户编号更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isDeptNameToNull())) {
        //     changed = true;
        //     newer.setDeptNameToNull(true); // 部门名称更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isParentCodeToNull())) {
        //     changed = true;
        //     newer.setParentCodeToNull(true); // 上级部门编号更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isSortIndexToNull())) {
        //     changed = true;
        //     newer.setSortIndexToNull(true); // 排序号(越小越靠前)更新为空值
        // }
        if (VerifyTools.isNotBlank(model.getSortIndexAdd()) && model.getSortIndexAdd() != 0) {
            changed = true;
            newer.setSortIndexAdd(model.getSortIndex()); // 排序号(越小越靠前)的增加值
        }
        // if (Boolean.TRUE.equals(model.isCreatorIdToNull())) {
        //     changed = true;
        //     newer.setCreatorIdToNull(true); // 创建人ID更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isCreatorNameToNull())) {
        //     changed = true;
        //     newer.setCreatorNameToNull(true); // 创建人姓名更新为空值
        // }
        return changed ? newer : null;
    }

}
